package com.ly.heart.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.ly.common.PageParam;
import com.ly.common.core.domain.AjaxResult;
import com.ly.common.core.domain.entity.SysDept;
import com.ly.common.core.domain.entity.SysUser;
import com.ly.common.exception.CustomException;
import com.ly.common.utils.DateUtils;
import com.ly.common.utils.SecurityUtils;
import com.ly.common.utils.StringUtils;
import com.ly.common.utils.erp.ConstUtil;
import com.ly.common.utils.erp.ReturnPage;
import com.ly.common.utils.erp.SnowflakeIdWorker;
import com.ly.heart.domain.*;
import com.ly.heart.domain.dto.KingCheckQueryDto;
import com.ly.heart.domain.dto.StartProcessDto;
import com.ly.common.core.domain.ActCurrentTaskVo;
import com.ly.heart.domain.vo.KingCheckVo;
import com.ly.heart.domain.vo.select.KingCheckSelectVo;
import com.ly.heart.domain.vo.select.query.KingCheckSelectQueryDto;
import com.ly.heart.mapper.KingCheckMapper;
import com.ly.heart.service.*;
import com.ly.heart.util.ChineseToPinyin;
import com.ly.heart.util.CurrentUserUtil;
import com.ly.system.service.ISysDeptService;
import com.ly.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;

/**
 * 金蝶-检验单Service业务层处理
 *
 * @author cxl
 * @date 2024-08-11
 */
@Service
public class KingCheckServiceImpl extends ServiceImpl<KingCheckMapper,KingCheckEntity> implements IKingCheckService {

    @Resource
    private KingCheckMapper kingCheckMapper;
    @Resource
    private ISysDeptService sysDeptService;
    @Resource
    private IKingCheckMaterialService checkMaterialService;
    @Resource
    private IKingCheckMaterialDetailService checkMaterialDetailService;
    @Resource
    private IKingCheckMaterialUseDecisionService checkMaterialUseDecisionService;
    @Resource
    private IKingReceiveNoticeMaterialService kingReceiveNoticeMaterialService;
    @Resource
    private IActModelService actModelService;
    @Resource
    private IActTaskCommentService actTaskCommentService;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private IKingBaseMeteringUnitService meteringUnitService;
    @Resource
    private ISupplierService supplierService;
    @Resource
    private IWarehouseService warehouseService;


    @Override
    public AjaxResult getKingCheckPageList(KingCheckQueryDto queryDto){
        List<KingCheckVo> list = checkMaterialService.getKingCheckMaterialList(queryDto);
        if(!CollectionUtils.isEmpty(list)){
            list.forEach(kingCheckVo -> {
                ActTaskCommentEntity actTaskCommentEntity = actTaskCommentService.queryLastComment(kingCheckVo.getInstanceId());
                if ( actTaskCommentEntity != null ) {
                    kingCheckVo.setApprovedUser ( actTaskCommentEntity.getApprovedUser () );
                    kingCheckVo.setRemark ( actTaskCommentEntity.getRemark () );
                }
                ActCurrentTaskVo currentTaskVo = actModelService.getCurrentTaskByInstanceId(kingCheckVo.getInstanceId());
                Optional.ofNullable(currentTaskVo).ifPresent(kingCheckVo::setCurrentTask);
            });
        }
        Page<KingCheckVo> page = new Page<>(queryDto.getPage(),queryDto.getLimit());
        return AjaxResult.success(ReturnPage.getReturnPage(page,list));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult draft(KingCheckEntity kingCheck){
        if(StringUtils.isEmpty(kingCheck.getId())){
            //设置检验单基本信息
            String kingCheckId = SnowflakeIdWorker.getInstance().nextStringId();
            Date nowDate = DateUtils.getNowDate();
            String userId = SecurityUtils.getLoginUser().getUser().getUserId();
            kingCheck.setId(kingCheckId).setUserId(userId).setCreateTime(nowDate).setCreateName(SecurityUtils.getUsername());
            //检验单单号生成
            if(StringUtils.isEmpty(kingCheck.getDocCode())){
                String companyId = CurrentUserUtil.getCompanyId();
                SysDept sysDept = sysDeptService.getById(companyId);
                int count = kingCheckMapper.queryCount();
                String countStr = String.format("%06d", count);
                String firstLetter = ChineseToPinyin.getFirstLetter(sysDept.getDeptName());
                String docCode = firstLetter.concat("_JYD_").concat(countStr);
                kingCheck.setDocCode(docCode);
            }
            List<KingCheckMaterialEntity> materialLists = kingCheck.getMaterialLists();
            if(!CollectionUtils.isEmpty(materialLists)){
                //保存物料信息
                saveMaterialAndDecision(kingCheck,materialLists);
            }
            //流程状态：暂存
            kingCheck.setState(ConstUtil.STATE_IN_DRAFT);
            boolean saveFlag = this.save(kingCheck);
            if (saveFlag) {
                return AjaxResult.success("暂存检验单成功！",kingCheck.getId());
            }
            return AjaxResult.error("暂存检验单失败！");
        }else{
            return update(kingCheck);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult submit(KingCheckEntity kingCheck){
        if ( StringUtils.isBlank ( kingCheck.getId () ) ) {
            return AjaxResult.error ("请先暂存该单据！");
        }
        if(CollectionUtils.isEmpty(kingCheck.getMaterialLists())){
            return AjaxResult.error("物料信息不能为空！");
        }
        //物料信息
        List<KingCheckMaterialEntity> materialLists = kingCheck.getMaterialLists();
        materialLists.forEach(checkMaterial -> {
            if(StringUtils.isNotEmpty(checkMaterial.getSourceType())){
                //检查检验单数量(源单分为：收料通知单,检验单两种，分别走不同的逻辑)
                if(checkMaterial.getSourceType().equals(ConstUtil.CHECK_SOURCE_TYPE_RECEIVE_NOTICE)){
                    checkMaterialNumByReceiveNotice(checkMaterial);
                }
                if (checkMaterial.getSourceType().equals(ConstUtil.CHECK_SOURCE_TYPE_CHECK)) {
                    checkMaterialNumByCheck(checkMaterial);
                }
            }
        });

        //删除暂存时保存的物料以及其他信息
        removeMaterialAndDetail(kingCheck.getId());
        //保存物料信息
        saveMaterialAndDecision(kingCheck,materialLists);
        //启动审批流程
        StartProcessDto startDto = new StartProcessDto().setBusinessId(kingCheck.getId()).setBusinessType(kingCheck.getBusinessType()).setModelId(kingCheck.getModelId());
        startDto.setBusinessName("检验单_".concat(kingCheck.getDocCode()));
        String instanceId = actModelService.startProcess(startDto);
        kingCheck.setState(ConstUtil.STATE_IN_PROCESS).setInstanceId(instanceId).setUpdateTime(DateUtils.getNowDate());
        boolean updated = this.updateById(kingCheck);
        if ( !updated ) {
            return AjaxResult.error( "提交检验单失败!" );
        }
        return AjaxResult.success ( "提交检验单成功!" );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(KingCheckEntity kingCheck){
        if(StringUtils.isEmpty(kingCheck.getId())){
            return AjaxResult.error("检验单id不能为空！");
        }
        //删除暂存时保存的物料以及其他信息
        removeMaterialAndDetail(kingCheck.getId());
        //物料信息
        List<KingCheckMaterialEntity> materialLists = kingCheck.getMaterialLists();
        //保存物料信息
        saveMaterialAndDecision(kingCheck,materialLists);
        boolean updated = this.updateById(kingCheck);
        if ( !updated ) {
            return AjaxResult.error( "修改失败!");
        }
        return AjaxResult.success ( "修改成功!",kingCheck.getId() );
    }

    /**
     * 收料通知单下推检验单
     * 检查物料明细数量
     * 一条物料信息里可能包含多条决策信息(接收;让步接收;挑选（全检）;判退)
     * @param kingCheckMaterial
     */
    private void checkMaterialNumByReceiveNotice(KingCheckMaterialEntity kingCheckMaterial){
        /**判断检验数量是否超过源单数量**/
        KingReceiveNoticeMaterialEntity receiveNoticeMaterial = kingReceiveNoticeMaterialService.getById(kingCheckMaterial.getSourceMaterialDetailId());
        double receiveNoticeNumber = Double.parseDouble(receiveNoticeMaterial.getDeliveryNum());
        //根据该收料通知单该物料查询已经检验的数量
        double sumCheckNum = 0;
        List<KingCheckMaterialEntity> kingCheckMaterials = checkMaterialService.list(new LambdaQueryWrapper<KingCheckMaterialEntity>().ne(KingCheckMaterialEntity::getCheckId,kingCheckMaterial.getCheckId()).eq(KingCheckMaterialEntity::getRelationId, kingCheckMaterial.getRelationId()).eq(KingCheckMaterialEntity::getSourceMaterialDetailId, kingCheckMaterial.getSourceMaterialDetailId()));
        if(!CollectionUtils.isEmpty(kingCheckMaterials)){
            sumCheckNum = kingCheckMaterials.stream().mapToDouble(checkMaterial -> Double.parseDouble(checkMaterial.getCheckNum())).sum();
        }
        //剩余可引用数量
        double surplusNum = receiveNoticeNumber - sumCheckNum;
        if (Double.parseDouble(kingCheckMaterial.getCheckNum()) > surplusNum) {
            throw new CustomException("引用数量不能超过收料通知单数量！");
        }
        /**检验单物料明细决策信息**/
        List<KingCheckMaterialUseDecisionEntity> decisionList = kingCheckMaterial.getDecisionList();
        if(CollectionUtils.isEmpty(decisionList)){
            throw new CustomException("物料检验决策信息不能为空！");
        }
        //判断物料明细决策里信息总数量是否超过明细数量
        double sumDecisionNum = decisionList.stream().mapToDouble(material -> Double.parseDouble(material.getNum())).sum();
        if(sumDecisionNum > Double.parseDouble(kingCheckMaterial.getCheckNum())){
            throw new CustomException("物料检验决策数量不能超过检验单明细数量！");
        }
    }

    /**
     * 检验单下推检验单
     * 挑选全检的数量
     * @param kingCheckMaterial
     */
    private void checkMaterialNumByCheck(KingCheckMaterialEntity kingCheckMaterial){
        //查询父检验单挑选(全检)数量
        List<KingCheckMaterialUseDecisionEntity> chooseList = checkMaterialUseDecisionService.list(new LambdaQueryWrapper<KingCheckMaterialUseDecisionEntity>()
            .eq(KingCheckMaterialUseDecisionEntity::getCheckId, kingCheckMaterial.getRelationId())
            .eq(KingCheckMaterialUseDecisionEntity::getCheckMaterialId, kingCheckMaterial.getSourceMaterialDetailId())
            .eq(KingCheckMaterialUseDecisionEntity::getUseDecision, ConstUtil.CHECK_DECISION_CHOOSE));
        double chooseSumNum = chooseList.stream().mapToDouble(decisionMaterial -> Double.parseDouble(decisionMaterial.getNum())).sum();
        //获取已经下推检验单的数量
        List<KingCheckMaterialEntity> checkMaterialList = checkMaterialService.list(new LambdaQueryWrapper<KingCheckMaterialEntity>().ne(KingCheckMaterialEntity::getCheckId,kingCheckMaterial.getCheckId()).eq(KingCheckMaterialEntity::getRelationId, kingCheckMaterial.getRelationId())
            .eq(KingCheckMaterialEntity::getSourceMaterialDetailId, kingCheckMaterial.getSourceMaterialDetailId())
            .eq(KingCheckMaterialEntity::getSourceType, ConstUtil.CHECK_SOURCE_TYPE_CHECK));
        double checkSumNum = 0;
        if(!CollectionUtils.isEmpty(checkMaterialList)){
            checkSumNum = checkMaterialList.stream().mapToDouble(checkMaterial -> Double.parseDouble(checkMaterial.getCheckNum())).sum();
        }
        double surplusNum = chooseSumNum - checkSumNum;
        if((Double.parseDouble(kingCheckMaterial.getCheckNum())) > surplusNum ){
            throw new RuntimeException("数量不能超过检验单数量！");
        }
    }

    /**
     * 保存物料信息以及决策信息
     * @param kingCheck
     * @param materialLists
     */
    private void saveMaterialAndDecision(KingCheckEntity kingCheck,List<KingCheckMaterialEntity> materialLists){
        materialLists.stream().filter(Objects::nonNull).forEach(checkMaterial -> {
            String checkMaterialId = SnowflakeIdWorker.getInstance().nextStringId();
            checkMaterial.setId(checkMaterialId).setCheckId(kingCheck.getId()).setSourceType(checkMaterial.getSourceType()).setUserId(kingCheck.getUserId()).setCreateTime(kingCheck.getCreateTime());
            boolean checkMaterialFlag = checkMaterialService.save(checkMaterial);
            if(!checkMaterialFlag){
                throw new RuntimeException("新增检验单物料信息失败！");
            }
            if(!CollectionUtils.isEmpty(checkMaterial.getDecisionList())){
                checkMaterial.getDecisionList().forEach(materialDecision -> {
                    materialDecision.setId(SnowflakeIdWorker.getInstance().nextStringId());
                    materialDecision.setCheckId(kingCheck.getId());
                    materialDecision.setCheckMaterialId(checkMaterialId);
                    materialDecision.setRelationId(checkMaterial.getRelationId());
                    materialDecision.setRelationCode(checkMaterial.getRelationCode());
                    materialDecision.setSourceMaterialDetailId(checkMaterial.getSourceMaterialDetailId());
                    materialDecision.setUserId(checkMaterial.getUserId());
                    materialDecision.setCreateTime(checkMaterial.getCreateTime());
                    checkMaterialUseDecisionService.save(materialDecision);
                });
            }
            Optional.ofNullable(checkMaterial.getMaterialDetail()).ifPresent(materialDetail -> {
                materialDetail.setId(SnowflakeIdWorker.getInstance().nextStringId());
                materialDetail.setCheckId(kingCheck.getId());
                materialDetail.setCheckMaterialId(checkMaterialId);
                materialDetail.setUserId(checkMaterial.getUserId());
                materialDetail.setCreateTime(checkMaterial.getCreateTime());
                checkMaterialDetailService.save(materialDetail);
            });
        });
    }

    /**
     * 查询金蝶-检验单
     * @param id 金蝶-检验单ID
     * @return 金蝶-检验单
     */
    @Override
    public KingCheckEntity selectKingCheckEntityById(String id)
    {
        KingCheckEntity checkEntity = kingCheckMapper.selectKingCheckEntityById(id);
        Optional.ofNullable(checkEntity).ifPresent(kingCheck -> {
            //质检组织
            SysDept checkOrg = sysDeptService.getOne(new LambdaQueryWrapper<SysDept>().eq(SysDept::getDeptCode, kingCheck.getCheckOrg()));
            if(Objects.nonNull(checkOrg)){
                kingCheck.setCheckOrgName(checkOrg.getDeptName());
            }
            //来源组织
            SysDept sourceOrg = sysDeptService.getOne(new LambdaQueryWrapper<SysDept>().eq(SysDept::getDeptCode, kingCheck.getSourceOrg()));
            if(Objects.nonNull(sourceOrg)){
                kingCheck.setSourceOrgName(sourceOrg.getDeptName());
            }
            //检验部门
            SysDept checkDept = sysDeptService.getOne(new LambdaQueryWrapper<SysDept>().eq(SysDept::getDeptCode, kingCheck.getCheckDept()));
            if(Objects.nonNull(checkDept)){
                kingCheck.setCheckDeptName(checkDept.getDeptName());
            }
            //质检员
            SysUser checkBy = sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserCode, kingCheck.getCheckBy()));
            if(Objects.nonNull(checkBy)){
                kingCheck.setCheckByName(checkBy.getUserName());
            }
            List<KingCheckMaterialEntity> kingCheckMaterialList = checkMaterialService.list(new LambdaQueryWrapper<KingCheckMaterialEntity>().eq(KingCheckMaterialEntity::getCheckId, kingCheck.getId()));
            if(!CollectionUtils.isEmpty(kingCheckMaterialList)){
                kingCheckMaterialList.forEach(checkMaterial -> {
                    //单位名称
                    if(StringUtils.isNotEmpty(checkMaterial.getUnit())){
                        KingBaseMeteringUnitEntity meteringUnitEntity = meteringUnitService.getOne(new LambdaQueryWrapper<KingBaseMeteringUnitEntity>().eq(KingBaseMeteringUnitEntity::getMeteringUnitCode, checkMaterial.getUnit()));
                        Optional.ofNullable(meteringUnitEntity).ifPresent(m -> {
                            checkMaterial.setUnitName(m.getMeteringUnitName());
                        });
                    }
                    //供应商名称
                    if(StringUtils.isNotEmpty(checkMaterial.getSupplierCode())){
                        SupplierEntity supplierEntity = supplierService.getOne(new LambdaQueryWrapper<SupplierEntity>().eq(SupplierEntity::getSupplierCode, checkMaterial.getSupplierCode()));
                        Optional.ofNullable(supplierEntity).ifPresent(s -> {
                            checkMaterial.setSupplierName(s.getSupplierName());
                        });
                    }
                    //仓库名称
                    if(StringUtils.isNotEmpty(checkMaterial.getWarehouseCode())){
                        WarehouseEntity warehouseEntity = warehouseService.getOne(new LambdaQueryWrapper<WarehouseEntity>().eq(WarehouseEntity::getWareCode, checkMaterial.getWarehouseCode()));
                        Optional.ofNullable(warehouseEntity).ifPresent(w -> {
                            checkMaterial.setWarehouseName(w.getWareName());
                        });
                    }
                    KingCheckMaterialDetailEntity checkMaterialDetail = checkMaterialDetailService.getOne(new LambdaQueryWrapper<KingCheckMaterialDetailEntity>().eq(KingCheckMaterialDetailEntity::getCheckId, kingCheck.getId()).eq(KingCheckMaterialDetailEntity::getCheckMaterialId, checkMaterial.getId()));
                    checkMaterial.setMaterialDetail(checkMaterialDetail);
                    List<KingCheckMaterialUseDecisionEntity> decisionList = checkMaterialUseDecisionService.list(new LambdaQueryWrapper<KingCheckMaterialUseDecisionEntity>().eq(KingCheckMaterialUseDecisionEntity::getCheckId, kingCheck.getId()).eq(KingCheckMaterialUseDecisionEntity::getCheckMaterialId, checkMaterial.getId()));
                    checkMaterial.setDecisionList(decisionList);
                });
                kingCheck.setMaterialLists(kingCheckMaterialList);
            }
        });
        return checkEntity;
    }

    /**
     * 查询金蝶-检验单列表
     *
     * @param kingCheckEntity 金蝶-检验单
     * @return 金蝶-检验单
     */
    @Override
    public List<KingCheckEntity> selectKingCheckEntityList(KingCheckEntity kingCheckEntity)
    {
        return kingCheckMapper.selectKingCheckEntityList(kingCheckEntity);
    }

    /**
     * 修改金蝶-检验单
     * @param kingCheckEntity 金蝶-检验单
     * @return 结果
     */
    @Override
    public int updateKingCheckEntity(KingCheckEntity kingCheckEntity)
    {
        kingCheckEntity.setUpdateTime(DateUtils.getNowDate());
        return kingCheckMapper.updateKingCheckEntity(kingCheckEntity);
    }

    /**
     * 根据检验单id删除物料以及其他信息
     * @param id
     */
    private void removeMaterialAndDetail(String id){
        checkMaterialService.remove(new LambdaQueryWrapper<KingCheckMaterialEntity>().eq(KingCheckMaterialEntity::getCheckId,id));
        checkMaterialDetailService.remove(new LambdaQueryWrapper<KingCheckMaterialDetailEntity>().eq(KingCheckMaterialDetailEntity::getCheckId,id));
        checkMaterialUseDecisionService.remove(new LambdaQueryWrapper<KingCheckMaterialUseDecisionEntity>().eq(KingCheckMaterialUseDecisionEntity::getCheckId,id));
    }

    /**
     * 批量删除金蝶-检验单
     * @param ids 需要删除的金蝶-检验单ID
     * @return 结果
     */
    @Override
    public int deleteKingCheckEntityByIds(String[] ids)
    {
        for(String id : ids){
            removeMaterialAndDetail(id);
        }
        return kingCheckMapper.deleteKingCheckEntityByIds(ids);
    }

    /**
     * 删除金蝶-检验单信息
     * @param id 金蝶-检验单ID
     * @return 结果
     */
    @Override
    public int deleteKingCheckEntityById(String id)
    {
        removeMaterialAndDetail(id);
        return kingCheckMapper.deleteKingCheckEntityById(id);
    }

    @Override
    public AjaxResult getKingCheckSelect(KingCheckSelectQueryDto queryDto) {
        queryDto.setPage(queryDto.getPage() - 1);
        List<KingCheckSelectVo> list = kingCheckMapper.getKingCheckSelect(queryDto);
        Integer totalCount = kingCheckMapper.queryTotalCount(queryDto);
        PageParam records = new PageParam ();
        records.setRecords ( list ).setTotal ( totalCount );
        return AjaxResult.success ( records );
    }


}
